
import asyncio
from typing import Any, List, Union
from httpx import Response
from minium import Page
from redis import Redis
from sqlalchemy import update, select
from initialization.redisInit import get_sync_redis
from model.entitys import Case, CaseGroup, to_json, SyncSession, get_sync_db, Status, Execut
from service import logger
from service.apiService import ApiService
from utils import business
from variable import dependent_data, reset_dependent_data
from appium.webdriver import WebElement as AppElement
from selenium.webdriver.remote.webelement import WebElement

def update_whether_by_web(session: SyncSession, result: Any, case_id: str, whether: str):
    session.query(Case).filter(Case.id == case_id).update({
        "actual_results": repr(result),
        "whether": whether
    })
    session.commit()

def update_result(session: SyncSession, api: ApiService, assert_info: str, expected_results: str,
                  actual_result_template: str,
                  result: Any, case_id: str,
                  num: dict, resp: Union[Response, List], element: Union[WebElement, AppElement],
                  is_unit: bool = False):
    try:
        if expected_results != "" and expected_results is not None:
            api.adh.recursive_search_key(result, True)

        if assert_info != "" and assert_info is not None:
            result = {}
            api.adh.result_assertion_by_dict(assert_info, resp, element, result)

    except AssertionError:
        whether = "fail"
        num["fail_number"] = num["fail_number"] + 1

    else:
        whether = "pass"
        num["pass_number"] = num["pass_number"] + 1

    if (assert_info == "" or assert_info is None) and expected_results != "" and expected_results is not None:
        # result = api.adh.matching_variable(actual_result_template)
        result = api.adh.new_matching_variable(actual_result_template)

    update_whether_by_web(session, result, case_id, whether)

    if is_unit is True and whether == "fail":
        raise AssertionError

def run_case(api: ApiService, gain_id: Union[str, List[str]], is_sched: bool = False, session: SyncSession = None,
             redis: Redis = None):
    if session is None:
        session = get_sync_db()

    if redis is None:
        redis = get_sync_redis()

    run_time = 3

    if isinstance(gain_id, List):
        if is_sched:
            business.clear_running_case(redis, gain_id)

        case_list = session.query(Case).filter(Case.id.in_(gain_id)).all()

    else:
        if is_sched:
            if redis.exists(gain_id):
                session.close()
                redis.close()

                return
            else:
                redis.set(gain_id, Execut.ACTIVE)

        case_group = session.query(CaseGroup).filter(CaseGroup.id == gain_id).first()
        run_time = case_group.rerun_times

        session.query(CaseGroup).filter(CaseGroup.id == gain_id).update({
            "executing": 1
        })
        session.commit()

        case_list = session.query(Case).filter(Case.case_group_id == gain_id).filter(Case.enable == Status.VALID).all()

    case_list = to_json(case_list)

    num = {
        "pass_number": 0,
        "fail_number": 0
    }

    for case in case_list:
        del case['case_group_id']
        del case['remarks']
        del case['createdAt']
        del case['updatedAt']

        for t in range(run_time):
            try:
                result, resp, element = api.implement_case(**case)

                update_result(session, api, case["assert_info"], case["expected_results"],
                                    case["actual_result_template"],
                                    result, case["id"], num, resp,
                                    element)

            except Exception as e:
                if t >= run_time - 1:
                    num["fail_number"] = num["fail_number"] + 1
                    update_whether_by_web(session, e, case["id"], "fail")

                else:
                    continue

            else:
                break

    if api.session is not None:
        api.session.close()
        api.engine.dispose()

    if api.driver is not None:
        api.playback()

        try:
            if isinstance(api.driver, Page):
                api.wxminium.shutdown()
            else:
                api.driver.quit()
        except Exception as e:
            logger.debug(repr(e))

    if isinstance(gain_id, str):
        session.query(CaseGroup).filter(CaseGroup.id == gain_id).update({
            "pass_number": num["pass_number"],
            "fail_number": num["fail_number"],
            "executing": 0
        })
    session.commit()

    if isinstance(gain_id, List):
        redis.delete(*gain_id)
    else:
        redis.delete(gain_id)

    session.close()

    redis.close()

    # reset_dependent_data()



































